#include <gtest/gtest.h>
#include <filesystem>

#include <helper/unittest/Tracer.h>

namespace fs = std::filesystem;

TEST(PathTest, test){
  const char * expect_path = "hello";
  fs::path p = expect_path;
  ASSERT_EQ(expect_path, p.native());

  { // test   operator "/"
    auto const && new_path = p / "world";
    ASSERT_EQ("hello/world", new_path.native());
  }
  {
    // test operator "/="
    p /= "world";
    ASSERT_EQ("hello/world", p.native());
  }

  { // test the has_root_name ???
    const char * parent_path = "hello";
    const char * relative_path = "hello/world";
    ASSERT_EQ(p.native(), relative_path);
    ASSERT_TRUE(false == p.has_root_name());
    ASSERT_EQ("", p.root_name());
    ASSERT_TRUE(false == p.has_root_directory());
    ASSERT_EQ("", p.root_directory());
    ASSERT_TRUE(false == p.has_root_path());
    ASSERT_EQ("", p.root_path());

    
    ASSERT_TRUE(p.has_relative_path());
    ASSERT_EQ(relative_path, p.relative_path());

    ASSERT_TRUE(p.has_parent_path());
    ASSERT_EQ(parent_path, p.parent_path());


    auto const && absolute_path = fs::absolute(p);
    ASSERT_TRUE(false == absolute_path.has_root_name());
    ASSERT_EQ("", absolute_path.root_name());

    ASSERT_TRUE(absolute_path.has_root_directory());
    ASSERT_EQ("/", absolute_path.root_directory());

    ASSERT_TRUE(absolute_path.has_root_path());
    ASSERT_EQ("/", absolute_path.root_path());

    //std::cout << absolute_path << std::endl;
  }

}

TEST(DirentryTest, testOneDirectory){
  const char * expect_dir = "tmp_dir";
  ASSERT_TRUE(false == fs::exists(expect_dir));

  ASSERT_TRUE(fs::create_directory(expect_dir));

  ASSERT_TRUE(fs::exists(expect_dir));

  

  EXPECT.reset();
  helper::unittest::Tracer tracer;
  for(auto & p: fs::directory_iterator(expect_dir)){
    tracer.operation(p.path().native());
  }
  ASSERT_EQ(EXPECT, tracer);


  fs::directory_entry dir(expect_dir);
  ASSERT_TRUE(dir.exists());
  
  ASSERT_TRUE(dir.is_directory());

  ASSERT_TRUE(fs::remove(expect_dir));
}

TEST(DiretryTest, testMultiDirectory){
  const char * expect_dir = "tmp_dir/sub_dir/grand_dir";
  ASSERT_TRUE(false == fs::exists(expect_dir));

  ASSERT_TRUE(fs::create_directories(expect_dir));


  auto const && top_dir = fs::path(expect_dir).parent_path().parent_path();

  
  //plain visit
  EXPECT.reset()
    .operation("tmp_dir/sub_dir")
    ;
  TRACER.reset();
  for(auto & p: fs::directory_iterator(top_dir)){
    TRACER.operation(p.path().native());
  }
  ASSERT_EQ(EXPECT, TRACER);

  //recursive visit 
  EXPECT.reset()
    .operation("tmp_dir/sub_dir")
    .operation("tmp_dir/sub_dir/grand_dir")
    ;
  TRACER.reset();
  for(auto & p : fs::recursive_directory_iterator(top_dir)){
    TRACER.operation(p.path().native());
  }
  ASSERT_EQ(EXPECT, TRACER);

  ASSERT_EQ((std::uintmax_t)3, fs::remove_all(top_dir));
}


#include <system_error>
TEST(SystemErrorTest, testErrorCode){
  std::error_code ec = std::make_error_code(std::errc::no_such_file_or_directory);
  if(ec == std::errc::no_such_file_or_directory){
    std::cout << "no such file or directory" << std::endl;
  }
  else{
    std::cout << "erro code = 0" << std::endl;
  }
  //ASSERT_EQ(ec, errc::no_such_file_or_directory);
}
